﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RayDen.Library.Core;
using RayDen.Library.Core.Noise;
using RayDen.Library.Core.Primitives;

namespace RayDen.Library.Components.Volume {
    using Spectrum = RgbSpectrum;

    public class DensityRegion : VolumeRegion {

        // DensityRegion Public Methods
        public DensityRegion(Spectrum sa, Spectrum ss, float gg, Spectrum emit, AABB b) {
            sig_a = sa;
            sig_s = ss;
            le = emit;
            g = gg;
            worldBound = b;
        }

        public override AABB WorldBound() {
            return worldBound;
        }


        public virtual float Density(ref Point Pobj) {
            return 0.1f * (1f / NoiseProvider.Instance.Noise((Vector)Pobj.Normalize()));
        }

        public override Spectrum sigma_a(ref Point p, ref Vector w, float t)
        {
            return Density(ref p) * sig_a;
        }

        public override Spectrum sigma_s(ref Point p, ref Vector w, float t)
        {
            return Density(ref p) * sig_s;
        }
        public override Spectrum sigma_t(ref Point p, ref Vector w, float t) {
            return Density(ref p) * (sig_a + sig_s);
        }
        public override Spectrum Lve(ref Point p, ref Vector w, float t)
        {
            return Density(ref p) * le;
        }
        public override float p(ref Point p, ref Vector w, ref Vector wp, float t)
        {
            //return PhaseFunctions.PhaseRayleigh(ref w, ref wp);
            return MathLab.INV4PI;
            //return PhaseFunctions.PhaseHG(ref w, ref wp, g);
        }

        public override Spectrum tau(RayInfo r, float stepSize, float offset) {
            float t0, t1;
            float length = r.Dir.Length;
            if (length == 0f) return RgbSpectrum.ZeroSpectrum();
            RayInfo rn = new RayInfo(r.Org, r.Dir / length, r.MinT * length, r.MaxT * length);
            if (!IntersectP(rn, out t0, out t1)) return RgbSpectrum.ZeroSpectrum();
            Spectrum tau = new RgbSpectrum();
            t0 += offset * stepSize;
            while (t0 < t1) {
                var pt = rn.Point(t0);
                var d = -rn.Dir;
                tau += sigma_t(ref pt, ref d, 1.0f);
                t0 += stepSize;
            }
            return tau * stepSize;
        }

        // DensityRegion Protected Data
        protected Spectrum sig_a, sig_s, le;
        protected float g;
        protected AABB worldBound;
        //Transform WorldToVolume;

        public override bool IntersectP(RayInfo ray, out float t0, out float t1) {
            return this.worldBound.Intersect(ray, out t0, out t1);
        }
    };


}
